﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using java.math;

namespace EpcTagLibrary.Pat
{
    public class PatternField
    {
        private static Regex p = new Regex("(\\d+)|\\[(\\d+)\\-(\\d+)\\]|(\\*)|(X)", RegexOptions.IgnoreCase);
        protected Match m;

        private bool m_IsWild = false;
        private bool m_IsRange = false;
        private bool m_IsGrouping = false;
        private BigInteger m_LowRange;
        private BigInteger m_HighRange;
        private BigInteger m_Exact;
        //private MethodInfo m_Method;
        private PropertyInfo m_Property;
        private string m_Component;

        public PatternField(string patComponent, bool isGroupingPattern, int maxBits)
        {
            m = p.Match(patComponent);
            if (!m.Success)
            {
                throw new PatternParseException("Invalid pattern component :" + patComponent);
            }

            m_Component = patComponent;

            if ((m.Groups[1].Value != null) && (m.Groups[1].Value.Length >0))
            {
                m_Exact = new BigInteger(m.Groups[1].Value, 10);                
            }
            else if ((m.Groups[2].Value != null) && (m.Groups[3].Value != null) && (m.Groups[2].Value.Length > 0) &&(m.Groups[3].Value.Length >0))
            {
                m_IsRange = true;
                m_LowRange = new BigInteger(m.Groups[2].Value, 10);
                m_HighRange = new BigInteger(m.Groups[3].Value, 10); 

                if (m_LowRange.compareTo(m_HighRange)>0)
                {
                    throw new PatternParseException("Invalid pattern component :" + patComponent);
                }
            }
            else if ((m.Groups[4].Value != null) && (m.Groups[4].Value.Length >0))
            {
                m_IsWild = true;
            }
            else if ((m.Groups[5].Value != null) && (m.Groups[5].Value.Length >0))
            {
                if (isGroupingPattern)
                {
                    m_IsWild = true;
                    m_IsGrouping = true;
                }
                else
                {
                    throw new PatternParseException("Invalid pattern component :" + patComponent);
                }
            }
        }

        public virtual bool MatchField(EPC epc)
        {
            bool Result = false;

            if (m_IsWild)
            {
                Result = true;
            }
            else
            {
                BigInteger Val;
                try
                {
                    if (m_Property.PropertyType == typeof(long))
                    {
                        Val = new BigInteger(m_Property.GetValue(epc, new object[0]).ToString(), 10);
                    }
                    else if (m_Property.PropertyType == typeof(int))
                    {
                        Val = new BigInteger(m_Property.GetValue(epc, new object[0]).ToString(), 10);
                    }
                    else if (m_Property.PropertyType == typeof(BigInteger))
                    {
                        Val = (BigInteger)m_Property.GetValue(epc, new object[0]);
                    }
                    else
                    {
                        throw new PatternMatchException("Matching error. Unknown field type " + m_Property.PropertyType.ToString());
                    }
                }
                catch (Exception e)
                {
                    throw new PatternParseException("Matching Error.", e);
                }

                Result = m_IsRange ? (Val.compareTo(m_LowRange) >=0) && (Val.compareTo( m_HighRange)<=0) : Val.compareTo(m_Exact)==0;
            }

            return Result;
        }

        public virtual GroupField GroupField(EPC epc, GroupField parent)
        {
            GroupField Result = null;

            if (MatchField(epc))
            {
                if (IsGrouping)
                {
                    try
                    {
                        Result = parent.FindOrAddGroup(this, ((long)m_Property.GetValue(epc, new object[0])).ToString());
                    }
                    catch (Exception e)
                    {
                        throw new PatternMatchException("Grouping Error.", e);
                    }
                }
                else
                {
                    Result = parent.FindOrAddGroup(this, Component);
                }
            }

            return Result;
        }

        public bool IsRange
        {
            get
            {
                return m_IsRange;
            }
        }

        public bool IsWild
        {
            get
            {
                return m_IsWild;
            }
        }

        public bool IsGrouping
        {
            get
            {
                return m_IsGrouping;
            }
        }

        public BigInteger LowRange
        {
            get
            {
                return m_LowRange;
            }
        }

        public BigInteger HighRange
        {
            get
            {
                return m_HighRange;
            }
        }

        public BigInteger Exact
        {
            get
            {
                return m_Exact;
            }
        }

        public PropertyInfo Property
        {
            get
            {
                return m_Property;
            }
            set
            {
                m_Property = value;
            }
        }

        public string Component
        {
            get
            {
                return m_Component;
            }
        }

        public override string ToString()
        {
            StringBuilder Result = new StringBuilder();

            Result.Append("PatternField(");
            Result.Append(m_Component);
            Result.Append("){");

            if (!IsRange && !IsWild)
            {
                Result.Append("Exact:");
                Result.Append(Exact);
            }
            else if (IsRange)
            {
                Result.Append("range:");
                Result.Append(LowRange);
                Result.Append("-");
                Result.Append(HighRange);
            }
            else
            {
                Result.Append("Any");
            }

            Result.Append("}");

            return Result.ToString();
        }
    }
}
